package utils
{

    import flash.display.Stage;
    import flash.events.ErrorEvent;
    import flash.events.UncaughtErrorEvent;
    import flash.system.Capabilities;

    import mx.utils.ObjectUtil;

    /**
     *  Logger tool aggregator. This class contain major type of log messages.
     */
	public class Logger
	{
        //-----------------------------
        // debug tools id
        //-----------------------------

        public static const FLASH_CONSOLE:uint = 1 << 2;
        public static const ARTHROPOD:uint = 1 << 3;
        public static const SAVE:uint = 1 << 4;
        public static const FLASH_TRACE:uint = 1 << 5;
        public static const MONSTER_DEBUGGER:uint = 1 << 6;
        public static const BROWSER_CONSOLE:uint = 1 << 7;


        //-----------------------------
        // toolId
        //-----------------------------

        private static var _toolId:uint = FLASH_TRACE | FLASH_CONSOLE | SAVE;

        public static function get toolId():uint
        {
            return _toolId;
        }


        //-----------------------------
        // isDebug flag
        //-----------------------------

        private static var _isDebug:Boolean = false;

        public static function get isDebug():Boolean
        {
            return _isDebug;
        }


        //-----------------------------
        // errorMessageCounter
        //-----------------------------

        private static var _errorMessageCounter:uint;

        public static function get errorMessageCounter():uint
        {
            return _errorMessageCounter;
        }


        //-----------------------------
        // errorMessageCounter
        //-----------------------------

        private static var _warningMessageCounter:uint;

        public static function get warningMessageCounter():uint
        {
            return _warningMessageCounter;
        }


        //-------------------------------------------------------------------
        // Methods
        //-------------------------------------------------------------------

        /**
         * Add to log debug message. This messages added to log only if
         * isDebug flag is true.
         *
         * @param source
         * @param args
         */
        public static function debug(source: Object, ...args):void
        {
            if (!_isDebug)
                return;
            var s:String = concatArguments(source, args);
            extDebug(s);
        }

        /**
         * Add to log custom record not belong to any group
         *
         * @param source
         * @param args
         */
		public static function print(source: Object, ...args): void
		{
            var s:String = concatArguments(source, args);
            extLog(s);
		}

        /**
         * Add to log information message
         *
         * @param source
         * @param args
         */
        public static function log(source:Object, ...args):void
        {
            var s:String = concatArguments(source, args);
            extLog(s);
        }

        /**
         * Add to log information message
         *
         * @param source
         * @param args
         */
        public static function info(source:Object, ...args):void
        {
            var s:String = concatArguments(source, args);
            extInfo(s);
        }

        /**
         * Add to log warning message.
         *
         * @param source
         * @param args
         */
        public static function warning(source:Object, ...args):void
        {
            var s:String = concatArguments(source, args);
            extWarning(s);
            _warningMessageCounter++;
        }

        /**
         * Add to log error message
         *
         * @param error
         * @param target
         * @param message
         */
        public static function error(error:*, target:Object, message:String=""):void
        {
            var str:String = "ERROR: " + getClassName(target);
            if (message)
                str += message + "\n";
            if (error is Error)
                str += (error as Error).message;
            if (error is ErrorEvent)
                str += (error as ErrorEvent).text;
            if (error is String)
                str += " " + String(error);
            extError(str);
            _errorMessageCounter++;
        }

        /**
         * Get all log messages for this work session. This property contain
         * store data only if SAVE toolId is on.
         */
        public static function get fullLog():String
        {
            return _fullLog;
        }

        /**
         * Initialize logger tool. Use this method before sending any log
         * message.
         *
         * @param stage is an application stage object. This property used for
         * attach log UI component to stage.
         *
         * @param consoleKey string with chars wich user need to type to show
         * log.
         *
         * @param toolId is an bitset of tools wich will used as external
         * logger.
         *
         * @param usePrefix if this flag is TRUE any log message will start
         * from appropriate prefix such as "ERROR", "WARNING", "INFO", "DEBUG"
         */
        public static function initialize(stage:Stage, consoleKey:String,
            toolId:uint=32, usePrefix:Boolean = false,
            addTimestamp:Boolean = false):void
        {
            Logger._toolId = toolId;

            // set isDebug
            _isDebug = Capabilities.playerType == "StandAlone";
            if (_isDebug)
            {
                consoleKey = "`";
            }

            stage.loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, stage_uncaughtErrorHandler)

//            com.demonsters.debugger.MonsterDebugger.initialize(stage);

//            Debug.INIT_DEBUG();
//            Debug.DEBUG("DEBUG INITED");

//            Cc.startOnStage(stage, consoleKey); // "`" - change for password. This will start hidden
//            Cc.visible = false; // Show console, because having password hides console.
//            Cc.height = 220; // change height. You can set x y width height to position/size the main panel
//            Cc.config.tracing = false; // Also trace on flash's normal trace
//            Cc.remoting = false; // Start sending logs to remote (using LocalConnection)
//            Cc.commandLine = true; // Show command line
//            Cc.config.commandLineAllowed = true; // enable advanced (but security risk) features.
        }

        private static function stage_uncaughtErrorHandler(event:UncaughtErrorEvent):void
        {
            error(event, event.target, "UNCAUGHT ERROR");
        }

        /**
         *
         * @param source
         * @param o
         */
        public static function traceObject( source: Object, o: Object ): void
		{
			extLog(source + "traceObject" + o);

			var val: *;
			for (var key:String in o)
			{
				val = o[ key ];
				print(source, "\t" + key + ":\t" + val + "\n");
				if ( val is Object )
					traceObject( source, val );
			}
		}



        //-------------------------------------------------------------------
        //
        //  Private
        //
        //-------------------------------------------------------------------

        private static var _fullLog:String = "";

        private static function getClassName(target:Object):String
        {
            var classInfo:Object = ObjectUtil.getClassInfo(target);
            var className:String = String(classInfo.name).split("::")[1];
            return className;
        }

        private static function concatArguments(source:Object, args:Array):String
        {
            var result:String = source ? source.toString() : "null ";
            return result + args.join(" ");
        }

        private static function extInfo(message:String):void
        {/*
			if (toolId & MONSTER_DEBUGGER)
				MonsterDebugger.trace(null, message);

			if (_toolId & FLASH_CONSOLE)
            {
                if (message.match(/^MVC:/i))
                    Cc.info(message);
                else
				    Cc.log(message);
            }

			if (toolId & ARTHROPOD)
				Debug.INFO(message);

			if (_toolId & FLASH_TRACE)
				trace(message);
*/
            if (_toolId & SAVE)
                _fullLog += message + "\n";
        }

        private static function extLog(message:String):void
        {/*
			if (toolId & MONSTER_DEBUGGER)
				MonsterDebugger.trace(null, message);

			if (_toolId & FLASH_CONSOLE)
            {
                if (message.match(/^MVC:/i))
                    Cc.info(message);
                else
				    Cc.log(message);
            }

			if (_toolId & ARTHROPOD)
				Debug.INFO(message);
*/
			if (_toolId & FLASH_TRACE)
				trace(message);

            if (_toolId & SAVE)
                _fullLog += message + "\n";
        }

        private static function extWarning(message:String):void
        {/*
            if (toolId & MONSTER_DEBUGGER)
                MonsterDebugger.trace(null, message);

            if (_toolId & FLASH_CONSOLE)
                Cc.warn(message);

            if (_toolId & ARTHROPOD)
                Debug.WARN(message);
*/
            if (_toolId & FLASH_TRACE)
                trace(message);

            if (_toolId & SAVE)
                _fullLog += message + "\n";
        }

        private static function extError(message:String):void
        {/*
            if (toolId & MONSTER_DEBUGGER)
                MonsterDebugger.trace(null, message);

            if (_toolId & FLASH_CONSOLE)
                Cc.error(message);

            if (_toolId & ARTHROPOD)
                Debug.ERROR(message);
*/
            if (_toolId & FLASH_TRACE)
                trace(message);

            if (_toolId & SAVE)
                _fullLog += message + "\n";
        }

        private static function extDebug(message:String):void
        {/*
            if (toolId & MONSTER_DEBUGGER)
                MonsterDebugger.trace(null, message);

            if (_toolId & FLASH_CONSOLE)
                Cc.debugch("DEBUG", message);

            if (_toolId & ARTHROPOD)
                Debug.DEBUG(message);
*/
            if (_toolId & FLASH_TRACE)
                trace(message);

            if (_toolId & SAVE)
                _fullLog += message + "\n";
        }
    }
}